#include "GL/GLVertexBuffer.h"
#include "Logger.h"
#include "Exception.h"

NS_B2D_BEGIN

const GLenum GLVertexAttribute::dataTypes[] =
{
	GL_FLOAT,	//ATTRIBUTE_POSITION
	GL_FLOAT,	//ATTRIBUTE_COLOR
	GL_FLOAT,	//ATTRIBUTE_NORMAL
	GL_FLOAT,	//ATTRIBUTE_TEXCOORD0
	GL_FLOAT	//ATTRIBUTE_TEXCOORD1
};

GLVertexBuffer::GLVertexBuffer(void)
	: mBufferName(0)
{
	create();
}

GLVertexBuffer::~GLVertexBuffer(void)
{
	destroy();
}

void GLVertexBuffer::resizeImpl(void)
{
	BindLock bind(mBufferName);

	if( isInitialised() == false )
		create();
	glBufferData(GL_ARRAY_BUFFER, mBufferSize, nullptr, GL_STATIC_DRAW); // TODO not static!
}

void GLVertexBuffer::create(void)
{
	// Check in case...
	if( isInitialised() == true )
		destroy();

	// Create and check
	glGenBuffers(1, &mBufferName);
	if( mBufferName == 0 )
	{
		B2D_THROW(Exception::GRAPHICS_API_EXCEPTION,
			"Could not create the OpenGL vertex buffer.");
	}
	else
	{
		B2D_LOG_DEBUG("Vertex buffer was created with id(%i)\n", mBufferName);
	}
}

void GLVertexBuffer::destroy(void)
{
	BindLock bind(mBufferName);

	if(isLocked() == true ) unlock();

	if( isInitialised() == true )
	{
		glDeleteBuffers(1, &mBufferName);
		B2D_LOG_DEBUG("Vertex buffer with id(%i) was destroyed\n", mBufferName);
		mBufferName = 0;
	}
}

void GLVertexBuffer::lockImpl(LockMode mode, void** dst, size_t offset, size_t size)
{
	BindLock bind(mBufferName);

	mLockOffset = offset;
	mLockSize = size;
	mTempData = new char[mLockSize];
	mLockedForWritting = mode != LockMode::READ_ONLY;

	if( mode == LockMode::WRITE_ONLY_DISCARD )
	{
		// If discarding then set lock data to 0  and clear buffer
		memset(mTempData, 0, mLockSize);
		glBufferData(GL_ARRAY_BUFFER, mBufferSize, nullptr, GL_STATIC_DRAW);
	}
	else
	{
		// Copy data to temp lock buffer
		glGetBufferSubData(GL_ARRAY_BUFFER, offset, size, mTempData);
	}

	*dst = mTempData;
}

void GLVertexBuffer::unlockImpl(void)
{
	BindLock bind(mBufferName);

	if( mLockedForWritting == true )
	{
		glBufferSubData(GL_ARRAY_BUFFER, mLockOffset, mLockSize, mTempData);
	}
	// Clear temp buffer
	SafeDeleteArray(mTempData);
}

NS_B2D_END